/**
 * 
 */
package decoder;

import structure.Line;

/**
 * Dient zum Decodieren der Opcodes. Wenn passender OpCode gefunden wurde, wird
 * die passende Befehlsmethode aus {@link Commands} aufgerufen.
 * @author Dorothee Kern und Patrick Lehmann
 *
 */
public class Decoder {

    /**
     * Durch Bit-Masken werden die Befehle herausgefiltert.
     * @param line Befehlszeile
     */
    public void decodeOpCode(Line line) {
        int opCode = line.getOpCode();

        if ((opCode & 0x3000) == 0) {
            //Gruppe 00

            switch (opCode) {
                case 0x64:
                    Commands.getInstance().comCLRWDT(line);
                    break;
                case 0x9:
                    Commands.getInstance().comRETFIE(line);
                    break;
                case 0x8:
                    Commands.getInstance().comRETURN(line);
                    break;
                case 0x63:
                    Commands.getInstance().comSLEEP(line);
                    break;
                case 0xF9F:
                    Commands.getInstance().comNOP(line);
                    break;
                default:
                    funcGroup00(line);
            }
        }


        if ((opCode & 0x3000) == 0x1000) {
            //Gruppe Bitorientiert
            funcBitOriented(line);
        }

        if ((opCode & 0x3000) == 0x2000) {
            //GOTO oder CALL
            funcGotoCall(line);

        }

        if ((opCode & 0x3000) == 0x3000) {
            //Literal und Controls
            funcLiteralControls(line);

        }

    }

    public void funcGotoCall(Line line) {
        switch (line.getOpCode() & 0x800) {
            //CALL
            case 0:
                Commands.getInstance().comCALL(line);
                break;
            //GOTO
            case 0x800:
                Commands.getInstance().comGOTO(line);
                break;
            default:
                ;
        }
    }

    public void funcBitOriented(Line line) {
        switch (line.getOpCode() & 0xC00) {
            //BCF
            case 0:
                Commands.getInstance().comBCF(line);
                break;
            //BSF
            case 0x400:
                Commands.getInstance().comBSF(line);
                break;
            //BTFSC
            case 0x800:
                Commands.getInstance().comBTFSC(line);
                break;
            //BTFSS
            case 0xC00:
                Commands.getInstance().comBTFSS(line);
                break;
            default:
                ;

        }
    }

    public void funcLiteralControls(Line line) {
        switch (line.getOpCode() & 0xC00) {
            //MOVLW
            case 0:
                Commands.getInstance().comMOVLW(line);
                break;
            //RETLW
            case 0x400:
                Commands.getInstance().comRETLW(line);
                break;
            //Aufruf fincBitOps
            case 0x800:
                funcBitOps(line);
                break;
            //Aufruf funcAddSub
            case 0xC00:
                funcAddSub(line);
                break;
            default:
                ;
        }

    }

    public void funcBitOps(Line line) {
        switch (line.getOpCode() & 0x300) {
            //IORLW
            case 0:
                Commands.getInstance().comIORLW(line);
                break;
            //ANDLW
            case 0x100:
                Commands.getInstance().comANDLW(line);
                break;
            //XORLW
            case 0x200:
                Commands.getInstance().comXORLW(line);
                break;
            default:
                ;
        }
    }

    public void funcAddSub(Line line) {
        switch (line.getOpCode() & 0x200) {
            //SUBLW
            case 0:
                Commands.getInstance().comSUBLW(line);
                break;
            //ADDLW
            case 0x200:
                Commands.getInstance().comADDLW(line);
                break;
            default:
                ;
        }
    }

    public void funcGroup00(Line line) {
        switch (line.getOpCode() & 0xF00) {
            //MOVWF
            case 0:
                Commands.getInstance().comMOVWF(line);
                break;
            //ruft funcClr auf
            case 0x100:
                funcClr(line);
                break;
            //SUBWF
            case 0x200:
                Commands.getInstance().comSUBWF(line);
                break;
            //DECF
            case 0x300:
                Commands.getInstance().comDECF(line);
                break;
            //IORWF
            case 0x400:
                Commands.getInstance().comIORWF(line);
                break;
            //ANDWF
            case 0x500:
                Commands.getInstance().comANDWF(line);
                break;
            //XORWF
            case 0x600:
                Commands.getInstance().comXORWF(line);
                break;
            //ADDWF
            case 0x700:
                Commands.getInstance().comADDWF(line);
                break;
            //MOVF
            case 0x800:
                Commands.getInstance().comMOVF(line);
                break;
            //COMF
            case 0x900:
                Commands.getInstance().comCOMF(line);
                break;
            //INCF
            case 0xA00:
                Commands.getInstance().comINCF(line);
                break;
            //DECFSZ
            case 0xB00:
                Commands.getInstance().comDECFSZ(line);
                break;
            //RRF
            case 0xC00:
                Commands.getInstance().comRRF(line);
                break;
            //RLF
            case 0xD00:
                Commands.getInstance().comRLF(line);
                break;
            //SWAPF
            case 0xE00:
                Commands.getInstance().comSWAPF(line);
                break;
            //INFSZ
            case 0xF00:
                Commands.getInstance().comINCFSZ(line);
                break;
            default:
        }
    }

    public void funcClr(Line line) {
        switch (line.getOpCode() & 0x80) {
            //CLRW
            case 0:
                Commands.getInstance().comCLRW(line);
                break;
            //CLRF
            case 0x80:
                Commands.getInstance().comCLRF(line);
                break;
            default:
        }
    }
}
